import java.util.ArrayList;

public class App {
	public static void main(String[] args) {
		IScheduler scheduler = null;
		String filename = null;
		int numberOfCores = 1;
		//
		// If the number of arguments is less than two, show usage and exit
		if(args.length < 3){
			usage();
		}
		//
		// Process arguments
		for (int i = 0; i < args.length; i++) {
			if (args[i].compareTo("--help") == 0) {
				usage();
			} 
			else if (args[i].compareTo("-RR") == 0) {
				scheduler = new RRScheduler(null);
			} 
			else if (args[i].compareTo("-FCFS") == 0) {
				scheduler = new FCFSScheduler(null);
			} 
			else if (args[i].compareTo("-SJF") == 0) {
				scheduler = new SJFScheduler(null);
			} 
			else if (args[i].compareTo("-f") == 0 && i + 1 < args.length) {
				filename = args[++i];
			} 
			else if (args[i].compareTo("-c") == 0 && i + 1 < args.length) {
				try {
					numberOfCores = Integer.parseInt(args[++i]);
					
					if(numberOfCores < 1){
						System.out.println("You need at least one CPU core.\n");
						usage();
					}
				} catch (NumberFormatException nfe) {
					System.out.println("Expected an integer.");
					System.out.println("This argument \"" + args[i] + "\" is not an integer.\n");
					usage();
				}
			}
			else {
				usage();
			}
		}
		//
		// Reads in process from a file that will be used to simulate
		ArrayList<ProcessArrival> processArrivalSet = new ReadProcesses().read(filename);
		//
		// Create new simulator passing the processArrivalSet and the number of cores to use
		Simulator sim = new Simulator(processArrivalSet, numberOfCores);
		//
		// Get the scheduler manager
		// Set the scheduler
		ScheduleManager mgr = sim.getScheduler();
		mgr.setScheduler(scheduler);
		//
		// Begin the simulation
		sim.run();
		
		// Output
		//
		ProcessControlBlockTable pcbs = sim.getProcessTable();
		
		int cycles = sim.getSimulationCycleCount();
		int processes = pcbs.getNumberOfProcesses();
		
		System.out.printf("Simulation executed %d processes over %d total cycles.\n", processes, cycles);
		System.out.printf("Throughput was %.5f processes/cycle\n\n", processes / (double) cycles);
		
		// TODO: Finish displaying statistical calculations
		// Perform statistical calculations and do any displaying of those calculations
		CalculateStatistics statistics = new CalculateStatistics(sim.getProcessTable().getProcessesBookkeeping());
		System.out.printf("Average response time was:\t %.5f cycles(s).\n", statistics.getAverageResponseTime());
		System.out.printf("Average waiting time was:\t %.5f cycles(s).\n", statistics.getAverageWaitingTime());
		System.out.printf("Average turnaround time was:\t %.5f cycles(s).\n", statistics.getAverageTurnaroundTime());
		System.out.printf("Average total CPU time was:\t %.5f cycles(s).\n\n", statistics.getAverageTotalCPUTime());
	
		int j = 1;
		for (CPU cpu : sim.getCPUs()) {
			long busy = cpu.getBusyCycles();
			long total = cpu.getTotalCycles();
			
			System.out.printf("CPU %d was busy %d out of %d cycles.\n", 
							  j, busy, total);
			System.out.printf("\tUtilization: %.5f%%\n\n", 
					  		  busy / (double) total * 100);
			++j;
		}
	
	}

	private static void usage() {
		//
		// Display the usage of this program
		System.out.println("java App [options]");
		System.out.println("Options:\n"
						+ "  --help         \t\tDisplay usage information\n"
						+ "  -RR            \t\tUse round robin scheduler\n"
						+ "  -FCFS          \t\tUse first come first serve scheduler\n"
						+ "  -SJF           \t\tUse shortest job first scheduler\n"
						+ "  -f [filename]  \t\tUse this filename to read in process list\n"
						+ "  -c [nmbOfCores]\t\tDefines the number of cores to be used; Default = 1");
		System.exit(0);
	}
}
